use crate::FileCommands;
use indicatif::{ProgressBar, ProgressStyle};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
use zip::write::FileOptions;
use zip::CompressionMethod;
use zip::ZipWriter;
use std::io::Write;

#[derive(Debug, Serialize, Deserialize)]
pub struct FileStats {
    pub total_files: usize,
    pub total_directories: usize,
    pub total_size: u64,
    pub file_types: HashMap<String, usize>,
    pub largest_files: Vec<(PathBuf, u64)>,
    pub oldest_file: Option<(PathBuf, chrono::DateTime<chrono::Utc>)>,
    pub newest_file: Option<(PathBuf, chrono::DateTime<chrono::Utc>)>,
}

impl FileStats {
    pub fn new() -> Self {
        Self {
            total_files: 0,
            total_directories: 0,
            total_size: 0,
            file_types: HashMap::new(),
            largest_files: Vec::new(),
            oldest_file: None,
            newest_file: None,
        }
    }
    
    pub fn add_file(&mut self, path: &Path, size: u64, modified: chrono::DateTime<chrono::Utc>) {
        self.total_files += 1;
        self.total_size += size;
        
        // 统计文件类型
        if let Some(ext) = path.extension() {
            let ext_str = ext.to_string_lossy().to_lowercase();
            *self.file_types.entry(ext_str).or_insert(0) += 1;
        }
        
        // 记录最大文件
        self.largest_files.push((path.to_path_buf(), size));
        self.largest_files.sort_by(|a, b| b.1.cmp(&a.1));
        if self.largest_files.len() > 10 {
            self.largest_files.pop();
        }
        
        // 记录最老和最新的文件
        if self.oldest_file.is_none() || modified < self.oldest_file.as_ref().unwrap().1 {
            self.oldest_file = Some((path.to_path_buf(), modified));
        }
        if self.newest_file.is_none() || modified > self.newest_file.as_ref().unwrap().1 {
            self.newest_file = Some((path.to_path_buf(), modified));
        }
    }
    
    pub fn add_directory(&mut self) {
        self.total_directories += 1;
    }
}

pub fn handle_file_commands(command: FileCommands, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
    match command {
        FileCommands::Stats { path, recursive, detailed, format } => {
            let stats = file_stats(&path, recursive, verbose)?;
            print_file_stats(&stats, detailed, &format)?;
        },
        FileCommands::Search { pattern, directory, extension, max_depth, regex } => {
            let results = search_files(&pattern, &directory, extension.as_deref(), max_depth, regex, verbose)?;
            print_search_results(&results, verbose);
        },
        FileCommands::Dedup { directory, delete, by_content } => {
            dedup_files(&directory, delete, by_content, verbose)?;
        },
        FileCommands::Sync { source, target, mode, exclude } => {
            sync_files(&source, &target, &mode, &exclude, verbose)?;
        },
        FileCommands::Compress { source, output, level } => {
            compress_files(&source, &output, level, verbose)?;
        },
        FileCommands::Extract { archive, output } => {
            extract_files(&archive, &output, verbose)?;
        },
    }
    Ok(())
}

fn file_stats(path: &Path, recursive: bool, verbose: bool) -> Result<FileStats, Box<dyn std::error::Error>> {
    let mut stats = FileStats::new();
    let pb = ProgressBar::new_spinner();
    pb.set_style(ProgressStyle::default_spinner()
        .template("{spinner:.green} {msg}")?
        .tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]));
    
    if path.is_file() {
        pb.set_message("分析文件...");
        let metadata = fs::metadata(path)?;
        let modified = metadata.modified()?.into();
        stats.add_file(path, metadata.len(), modified);
    } else if path.is_dir() {
        pb.set_message("扫描目录...");
        
        let walker = if recursive {
            WalkDir::new(path).into_iter()
        } else {
            WalkDir::new(path).max_depth(1).into_iter()
        };
        
        for entry in walker.filter_map(|e| e.ok()) {
            if entry.file_type().is_dir() {
                stats.add_directory();
            } else if entry.file_type().is_file() {
                if let Ok(metadata) = entry.metadata() {
                    let modified = metadata.modified().unwrap_or_else(|_| std::time::SystemTime::UNIX_EPOCH).into();
                    stats.add_file(entry.path(), metadata.len(), modified);
                }
            }
            pb.tick();
        }
    }
    
    pb.finish_with_message("✅ 分析完成");
    Ok(stats)
}

fn search_files(
    pattern: &str, 
    directory: &Path, 
    extension: Option<&str>, 
    max_depth: Option<usize>,
    use_regex: bool,
    verbose: bool
) -> Result<Vec<PathBuf>, Box<dyn std::error::Error>> {
    let mut results = Vec::new();
    let pb = ProgressBar::new_spinner();
    pb.set_message("搜索文件...");
    
    let regex_pattern = if use_regex {
        Some(regex::Regex::new(pattern)?)
    } else {
        None
    };
    
    let walker = if let Some(depth) = max_depth {
        WalkDir::new(directory).max_depth(depth).into_iter()
    } else {
        WalkDir::new(directory).into_iter()
    };
    
    for entry in walker.filter_map(|e| e.ok()) {
        if entry.file_type().is_file() {
            let filename = entry.file_name().to_string_lossy();
            let path = entry.path();
            
            // 检查扩展名过滤
            let ext_match = if let Some(ext) = extension {
                path.extension().map_or(false, |e| e.to_string_lossy().eq_ignore_ascii_case(ext))
            } else {
                true
            };
            
            // 检查模式匹配
            let pattern_match = if let Some(ref regex) = regex_pattern {
                regex.is_match(&filename)
            } else {
                filename.contains(pattern)
            };
            
            if ext_match && pattern_match {
                results.push(path.to_path_buf());
                if verbose {
                    println!("找到: {}", path.display());
                }
            }
        }
        pb.tick();
    }
    
    pb.finish_with_message("✅ 搜索完成");
    Ok(results)
}

fn dedup_files(directory: &Path, delete: bool, by_content: bool, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
    let mut file_hashes: HashMap<u64, Vec<PathBuf>> = HashMap::new();
    let pb = ProgressBar::new_spinner();
    pb.set_message("计算文件哈希...");
    
    for entry in WalkDir::new(directory).into_iter().filter_map(|e| e.ok()) {
        if entry.file_type().is_file() {
            if let Ok(contents) = fs::read(entry.path()) {
                use std::collections::hash_map::DefaultHasher;
                use std::hash::{Hash, Hasher};
                
                let mut hasher = DefaultHasher::new();
                if by_content {
                    contents.hash(&mut hasher);
                } else {
                    // 只基于文件名和大小
                    let filename = entry.file_name().to_string_lossy();
                    filename.hash(&mut hasher);
                    contents.len().hash(&mut hasher);
                }
                let hash = hasher.finish();
                
                file_hashes.entry(hash).or_insert_with(Vec::new).push(entry.path().to_path_buf());
            }
        }
        pb.tick();
    }
    
    pb.finish_with_message("✅ 哈希计算完成");
    
    let mut duplicates = 0;
    for (_, files) in file_hashes {
        if files.len() > 1 {
            duplicates += files.len() - 1;
            println!("发现重复文件组 ({} 个文件):", files.len());
            for (i, file) in files.iter().enumerate() {
                if i == 0 {
                    println!("  📌 保留: {}", file.display());
                } else {
                    println!("  🗑️  重复: {}", file.display());
                    if delete {
                        fs::remove_file(file)?;
                        println!("    ✅ 已删除");
                    }
                }
            }
        }
    }
    
    if duplicates == 0 {
        println!("✅ 未发现重复文件");
    } else if !delete {
        println!("💡 使用 --delete 参数执行删除操作");
    }
    
    Ok(())
}

fn sync_files(source: &Path, target: &Path, mode: &str, exclude: &[String], verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
    if !source.exists() {
        return Err("源目录不存在".into());
    }
    
    if !target.exists() {
        fs::create_dir_all(target)?;
    }
    
    let pb = ProgressBar::new_spinner();
    pb.set_message("同步文件...");
    
    for entry in WalkDir::new(source).into_iter().filter_map(|e| e.ok()) {
        if entry.file_type().is_file() {
            let relative_path = entry.path().strip_prefix(source)?;
            let target_path = target.join(relative_path);
            
            // 检查排除模式
            let should_exclude = exclude.iter().any(|pattern| {
                relative_path.to_string_lossy().contains(pattern)
            });
            
            if should_exclude {
                continue;
            }
            
            // 创建目标目录
            if let Some(parent) = target_path.parent() {
                fs::create_dir_all(parent)?;
            }
            
            // 根据模式决定是否复制
            let should_copy = match mode {
                "mirror" => true,
                "update" => {
                    !target_path.exists() || 
                    entry.metadata()?.modified()? > fs::metadata(&target_path)?.modified()?
                },
                "backup" => {
                    let backup_path = target_path.with_extension("bak");
                    !backup_path.exists()
                },
                _ => false,
            };
            
            if should_copy {
                fs::copy(entry.path(), &target_path)?;
                if verbose {
                    println!("同步: {} -> {}", entry.path().display(), target_path.display());
                }
            }
        }
        pb.tick();
    }
    
    pb.finish_with_message("✅ 同步完成");
    Ok(())
}

fn compress_files(source: &Path, output: &Path, level: u8, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
    let file = fs::File::create(output)?;
    let mut zip = ZipWriter::new(file);
    
    let pb = ProgressBar::new_spinner();
    pb.set_message("压缩文件...");
    
    let compression_method = match level {
        1..=3 => CompressionMethod::Deflated,
        4..=6 => CompressionMethod::Deflated,
        7..=9 => CompressionMethod::Deflated,
        _ => CompressionMethod::Stored,
    };
    
    let options = FileOptions::default()
        .compression_method(compression_method)
        .unix_permissions(0o755);
    
    for entry in WalkDir::new(source).into_iter().filter_map(|e| e.ok()) {
        if entry.file_type().is_file() {
            let relative_path = entry.path().strip_prefix(source)?;
            let path_str = relative_path.to_string_lossy();
            
            zip.start_file(path_str.as_ref(), options)?;
            let mut file = fs::File::open(entry.path())?;
            std::io::copy(&mut file, &mut zip)?;
            
            if verbose {
                println!("压缩: {}", entry.path().display());
            }
        }
        pb.tick();
    }
    
    zip.finish()?;
    pb.finish_with_message("✅ 压缩完成");
    Ok(())
}

fn extract_files(archive: &Path, output: &Path, verbose: bool) -> Result<(), Box<dyn std::error::Error>> {
    let file = fs::File::open(archive)?;
    let mut archive = zip::ZipArchive::new(file)?;
    
    let pb = ProgressBar::new_spinner();
    pb.set_message("解压文件...");
    
    for i in 0..archive.len() {
        let mut file = archive.by_index(i)?;
        let outpath = output.join(file.name());
        
        if file.name().ends_with('/') {
            fs::create_dir_all(&outpath)?;
        } else {
            if let Some(p) = outpath.parent() {
                if !p.exists() {
                    fs::create_dir_all(p)?;
                }
            }
            let mut outfile = fs::File::create(&outpath)?;
            std::io::copy(&mut file, &mut outfile)?;
            
            if verbose {
                println!("解压: {}", outpath.display());
            }
        }
        pb.tick();
    }
    
    pb.finish_with_message("✅ 解压完成");
    Ok(())
}

fn print_file_stats(stats: &FileStats, detailed: bool, format: &str) -> Result<(), Box<dyn std::error::Error>> {
    match format {
        "json" => {
            println!("{}", serde_json::to_string_pretty(stats)?);
        },
        "yaml" => {
            println!("{}", serde_yaml::to_string(stats)?);
        },
        "table" => {
            println!("\n📊 文件统计结果:");
            println!("  总文件数: {}", stats.total_files);
            println!("  总目录数: {}", stats.total_directories);
            println!("  总大小: {} 字节", stats.total_size);
            
            if detailed {
                println!("  平均文件大小: {} 字节", 
                    if stats.total_files > 0 { stats.total_size / stats.total_files as u64 } else { 0 });
            }
            
            if !stats.file_types.is_empty() {
                println!("  文件类型分布:");
                let mut sorted_types: Vec<_> = stats.file_types.iter().collect();
                sorted_types.sort_by(|a, b| b.1.cmp(a.1));
                for (ext, count) in sorted_types {
                    println!("    .{}: {} 个文件", ext, count);
                }
            }
            
            if detailed && !stats.largest_files.is_empty() {
                println!("  最大文件:");
                for (file, size) in &stats.largest_files {
                    println!("    {}: {} 字节", file.display(), size);
                }
            }
            
            if detailed {
                if let Some((file, time)) = &stats.oldest_file {
                    println!("  最老文件: {} ({})", file.display(), time.format("%Y-%m-%d %H:%M:%S"));
                }
                if let Some((file, time)) = &stats.newest_file {
                    println!("  最新文件: {} ({})", file.display(), time.format("%Y-%m-%d %H:%M:%S"));
                }
            }
        },
        _ => return Err("不支持的输出格式".into()),
    }
    Ok(())
}

fn print_search_results(results: &[PathBuf], verbose: bool) {
    println!("\n🔍 搜索结果 ({} 个文件):", results.len());
    for file in results {
        println!("  {}", file.display());
    }
    
    if verbose && !results.is_empty() {
        println!("\n📋 详细信息:");
        for file in results {
            if let Ok(metadata) = fs::metadata(file) {
                let size = metadata.len();
                let modified = metadata.modified().unwrap_or_else(|_| std::time::SystemTime::UNIX_EPOCH);
                println!("  {} ({} 字节, 修改时间: {:?})", file.display(), size, modified);
            }
        }
    }
}


